package com.dkts.oil.test;


import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.time.Instant;
import java.util.*;

public class FleetClusteringGeoJsonExporter {

    private static final double DISTANCE_THRESHOLD = 0.01; // 控制轨迹点间距离的聚类阈值，可调
    private static final long MAX_TIME_GAP_SECONDS = 40 * 60; // 40分钟

    public static void main(String[] args) throws Exception {
        File csvFile = new File("C:\\Users\\heyou\\Documents\\WeChat Files\\wxid_86da35bc9zvi21\\FileStorage\\File\\2025-05\\c9a6717b7d2f5293cf7cd2ed05a0494c_2e2437ef9cd58c0d39af05569deeb4be_8.csv");
        CSVParser parser = CSVFormat.DEFAULT.withFirstRecordAsHeader().parse(new FileReader(csvFile));

        Map<String, List<TrajectoryPoint>> mmsiMap = new HashMap<>();
        for (CSVRecord record : parser) {
            String mmsi = record.get("mmsi");
            double lat = Double.parseDouble(record.get("lat"));
            double lon = Double.parseDouble(record.get("lon"));
            long timestamp = Long.parseLong(record.get("time"));
            mmsiMap.computeIfAbsent(mmsi, k -> new ArrayList<>())
                    .add(new TrajectoryPoint(mmsi, lat, lon, timestamp));
        }

        // 将所有轨迹点按mmsi聚合为轨迹
        List<Trajectory> trajectories = new ArrayList<>();
        for (Map.Entry<String, List<TrajectoryPoint>> entry : mmsiMap.entrySet()) {
            entry.getValue().sort(Comparator.comparingLong(p -> p.timestamp));
            trajectories.add(new Trajectory(entry.getKey(), entry.getValue()));
        }

        // 对轨迹做基于相似度（简单距离和时间约束）的聚类（编队识别）
        List<List<Trajectory>> fleets = clusterBySimilarity(trajectories);

        ObjectMapper mapper = new ObjectMapper();
        Files.createDirectories(Paths.get("output_fleets"));

        int groupId = 1;
        for (List<Trajectory> group : fleets) {
            ObjectNode fc = mapper.createObjectNode();
            fc.put("type", "FeatureCollection");
            ArrayNode features = mapper.createArrayNode();

            for (Trajectory traj : group) {
                ObjectNode feature = mapper.createObjectNode();
                feature.put("type", "Feature");

                ObjectNode geometry = mapper.createObjectNode();
                geometry.put("type", "LineString");
                ArrayNode coordinates = mapper.createArrayNode();
                for (TrajectoryPoint p : traj.points) {
                    ArrayNode coord = mapper.createArrayNode();
                    coord.add(p.lon);
                    coord.add(p.lat);
                    coordinates.add(coord);
                }
                geometry.set("coordinates", coordinates);
                feature.set("geometry", geometry);

                ObjectNode props = mapper.createObjectNode();
                props.put("mmsi", traj.mmsi);
                feature.set("properties", props);

                features.add(feature);
            }

            fc.set("features", features);
            mapper.writerWithDefaultPrettyPrinter().writeValue(
                    new FileWriter("output_fleets/fleet_group_" + groupId++ + ".geojson"), fc);
        }

        System.out.println("同编队轨迹GeoJSON已输出至 output_fleets 目录下");
    }

    private static List<List<Trajectory>> clusterBySimilarity(List<Trajectory> trajectories) {
        List<List<Trajectory>> clusters = new ArrayList<>();
        boolean[] visited = new boolean[trajectories.size()];

        for (int i = 0; i < trajectories.size(); i++) {
            if (visited[i]) continue;
            List<Trajectory> cluster = new ArrayList<>();
            cluster.add(trajectories.get(i));
            visited[i] = true;

            for (int j = 0; j < trajectories.size(); j++) {
                if (i == j || visited[j]) continue;
                if (isSimilar(trajectories.get(i), trajectories.get(j))) {
                    cluster.add(trajectories.get(j));
                    visited[j] = true;
                }
            }
            clusters.add(cluster);
        }

        return clusters;
    }

    private static boolean isSimilar(Trajectory t1, Trajectory t2) {
        for (TrajectoryPoint p1 : t1.points) {
            for (TrajectoryPoint p2 : t2.points) {
                long dt = Math.abs(p1.timestamp - p2.timestamp);
                double dx = p1.lon - p2.lon;
                double dy = p1.lat - p2.lat;
                double dist = Math.sqrt(dx * dx + dy * dy);
                if (dt <= MAX_TIME_GAP_SECONDS && dist <= DISTANCE_THRESHOLD) {
                    return true;
                }
            }
        }
        return false;
    }

    static class TrajectoryPoint {
        String mmsi;
        double lat;
        double lon;
        long timestamp;

        public TrajectoryPoint(String mmsi, double lat, double lon, long timestamp) {
            this.mmsi = mmsi;
            this.lat = lat;
            this.lon = lon;
            this.timestamp = timestamp;
        }
    }

    static class Trajectory {
        String mmsi;
        List<TrajectoryPoint> points;

        public Trajectory(String mmsi, List<TrajectoryPoint> points) {
            this.mmsi = mmsi;
            this.points = points;
        }
    }
}
